/********************************************************************************
 * Copyright (c)2016-2020, ShenZhen WanJiaAn Technology CO.,LTD.
 * All Rights Reserved.
 *
 * File Name     : UpgradeRecovery.c
 * Author        : JiangWendao
 * Date          : 2020-04-10
 *
 * Record        :
 * 1.Date        : 2020-04-10
 *   Author      : JiangWendao
 *   Modification: Created file
 ********************************************************************************/
#include "curl.h"
#include "app_common.h"
#include "DevConfig.h"
#include "Net.h"
#include "System.h"
#include "DevSocSub.h"
#include "UpgradeRecovery.h"

static UPGRADE_STATUS_TYPE_E gs_upgradeReocveryStatus = UPGRADE_STATUS_INIT;
static int gs_nFileLenght = 0;
static int gs_nDownloadLenght = 0;
static char g_outIp[32] = "";

static size_t writefile_callback(void *ptr, size_t size, size_t nmemb, void *stream)
{
	static int count = 0;
	int len = size * nmemb;
	int written = len;

	if (stream)
	{
		len = fwrite(ptr, size , nmemb, (FILE*)stream);
		gs_nDownloadLenght += written;

		if (count++ > 200)
		{
			count = 0;
			printf("filesize:%d download size[%d] :%d\%\n",gs_nFileLenght,
				gs_nDownloadLenght, gs_nDownloadLenght*100/gs_nFileLenght );
		}
	}
	
	return written;
}

static int file_exists(char *filename) {  
    return (access(filename, 0) == 0);  
}  

int HttpsDownLoad(const char *Url)
{
    LOGW("upgrade============>>>>\n");
	int i = 0;
	CURL *curl;  
	FILE *UpgradeFp = NULL;
	int  nFileLenght = 0;
    CURLcode res = CURLE_RECV_ERROR;

	remove(UPGRADE_RECOVERY_FILE);
	UpgradeFp = fopen(UPGRADE_RECOVERY_FILE, "wb");
	if (UpgradeFp == NULL) {
	    LOGE("fopen %s failed\n", UPGRADE_RECOVERY_FILE);
        return -1;
	}

	//尝试下载5次
	for ( i = 0; i < 5; i++)
	{
		curl = curl_easy_init();
		if (curl)
		{
			curl_easy_setopt(curl, CURLOPT_URL, Url);
			//option	
			curl_easy_setopt(curl, CURLOPT_DNS_CACHE_TIMEOUT, 15L);
			curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 15L);
			curl_easy_setopt(curl, CURLOPT_LOW_SPEED_LIMIT, 1L);
			curl_easy_setopt(curl, CURLOPT_LOW_SPEED_TIME, 15L);
			curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0); // 跳过证书检查
			curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);	// 从证书中检查SSL加密算法是否存在

			curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writefile_callback);
			curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)UpgradeFp);
			res = curl_easy_perform(curl);
			curl_easy_cleanup(curl);
			if (CURLE_OK == res) {
				break;
			}
		}
		else
		{
			LOGW("CURL curl_easy_init ERROR!!!!\n");
		}
	}
	fclose(UpgradeFp);
	UpgradeFp = NULL;
	return res;
}

int OnUpgradeByHttp(UPGRADE_STATUS_TYPE_E enUpgradeStatus)
{
	int nRet = -1;
	char upgradeURL[512] = {0};
	char upgradeCmd[512] = {0};
	char md5[128] = {0};
	int fileLenght = 0;

	/* get upgrade info */
	PowerSetWakeLock("upgrade recovery");	
	nRet = UpgradeRecoveryGetInfo(upgradeURL, md5, &fileLenght);
	if(-1 == nRet || strlen(upgradeURL) == 0) {
	    LOGE("UpgradeRecoveryGetInfo failed or upgradeURL is blank!\n");
	    nRet = -1;
		goto free_lock;
	}
	
	gs_nFileLenght = fileLenght;
	if (enUpgradeStatus == UPGRADE_STATUS_SHUTDOWN_FAIL) {
		UpgradeInit(fileLenght);
	}
	
	/* down upgrade file */
	nRet = HttpsDownLoad((const char *)upgradeURL);
	if(CURLE_OK != nRet) {
	    LOGE("HttpsDownLoad failed\n");
		remove(UPGRADE_RECOVERY_FILE);
        nRet = -1;
        goto free_lock;
	}
		
	nRet = UpgradeRun(UPGRADE_RECOVERY_FILE);
	UpgradeDeinit();
	PowerSetSocSleepTime(1, 10);
	if (nRet == 0) {
		UpgradeRecoverySetState(0);
		UpgradeRecoverySetRetryCnt(0);
	}

free_lock:
    PowerSetWakeUnLock("upgrade recovery");
	return nRet;
}

int UpgradeRecoverySetInfo(char *url, char *md5, int pktSize)
{
	UPGRADE_CONFIG stUpgradeInfo;

    memset(&stUpgradeInfo, 0, sizeof(stUpgradeInfo));
    snprintf(stUpgradeInfo.downUrl, sizeof(stUpgradeInfo.downUrl), "%s", url);
    snprintf(stUpgradeInfo.md5, sizeof(stUpgradeInfo.md5), "%s", md5);
    stUpgradeInfo.pktSize = pktSize;
    
	DevConfigSetUpgradeInfo(stUpgradeInfo);

	return 0;
}

int UpgradeRecoveryGetInfo(char *pUrl, char *pMd5, int *pPktSize)
{
    if (pUrl == NULL || pMd5 == NULL || pPktSize == NULL) {
        LOGE("Param is invalid!\n");
        return -1;
    }
    
	UPGRADE_CONFIG stUpgradeInfo;
    memset(&stUpgradeInfo, 0, sizeof(stUpgradeInfo));
	DevConfigGetUpgradeInfo(&stUpgradeInfo);

    sprintf(pUrl, "%s", stUpgradeInfo.downUrl);
    sprintf(pMd5, "%s", stUpgradeInfo.md5);
    *pPktSize = stUpgradeInfo.pktSize;
    
	return 0;
}

int UpgradeRecoverySetState(int upgradeState)
{
    return DevConfigSetUpgradeState(upgradeState);
}

int UpgradeRecoveryGetState(int *pUpgradeState)
{
    return DevConfigGetUpgradeState(pUpgradeState);
}

int UpgradeRecoverySetRetryCnt(int retryCnt)
{
    return DevConfigSetUpgradeRetryCnt(retryCnt);
}

int UpgradeRecoveryGetRetryCnt(int *pRetryCnt)
{
    return DevConfigGetUpgradeRetryCnt(pRetryCnt);
}

void *UpgradeRecoveryThread(void*args)
{
	SET_THREAD_NAME("UpgradeRecoveryThread");
    pthread_detach(pthread_self());
	
	time_t start_time = time(NULL);
	static time_t curTime = 0;
	
	while (1)
	{	
		NetLiteosGetAddrInfo("www.baidu.com", g_outIp);
		if (strlen(g_outIp) > 0)
			break;

		if (curTime - start_time >= 120)
		{
			printf("DOTWifiConfigThread NetLiteosGetAddrInfo failed\n");
			break;
		}

		usleep(50* 1000);
	}

	pthread_exit(0);
}

int UpgradeRecoveryProcess(UPGRADE_STATUS_TYPE_E enUpgradeStatus)
{
    LOGI("Test\n");
    
	int i = 0;//120秒没网睡眠
	char outIp[32] = "";
	int ret = -1;
	static char upgradeRetryCnt = 0;

	pthread_t UpgradeRecoveryPid;
	int err = pthread_create(&UpgradeRecoveryPid, NULL, &UpgradeRecoveryThread, NULL);
	if (err != 0) {
		LOGE("pthread_create UpgradeRecoveryThread failed!\n");
		return -1;
	}
	
	for (i = 0; i < 120; i++)
	{
		if (strlen(g_outIp) > 0) {
			ret = 0;
			break;
		}
		sleep(1);
	}

	if (i == 120)
	{
		return -1;
	}

	if (0 == ret)
	{//网络通了,继续升级
		ret = OnUpgradeByHttp(enUpgradeStatus);
		if (ret < 0) {
		    if (++upgradeRetryCnt >= 3) { //升级重试最大次数
		        LOGE("OnUpgradeByHttp failed, upgradeRetryCnt is %d\n", upgradeRetryCnt);
#ifndef MINI_APP	
				int retryCnt = 0;
				UpgradeRecoveryGetRetryCnt(&retryCnt);
				LOGW("retryCnt: %d\n", retryCnt);
				retryCnt++;
				UpgradeRecoverySetRetryCnt(retryCnt);
#endif /* MINI_APP */
                return -1;
		    }
		} else {
            SystemReboot("upgrade recovery successs");
		}
	}
	else
	{//睡眠
		printf("UpgradeRecoveryProcess failed\n");
		PowerSetWakeUnLock("upgrade recovery");
		PowerSetSocSleepTime(1, 10);
		return -1;
	}

	return 0;
}

void *tskUpgradeRecovery(void *args)
{
    SET_THREAD_NAME("tskUpgradeRecovery");
    pthread_detach(pthread_self());

    int ret = 0;

    while (1)
    {
        switch (gs_upgradeReocveryStatus)
        {
            case UPGRADE_STATUS_DOWNLOAD_FAIL:
            case UPGRADE_STATUS_EXECUT_FAIL:
            case UPGRADE_STATUS_SHUTDOWN_FAIL://关机重启升级
                {			
                    ret = UpgradeRecoveryProcess(gs_upgradeReocveryStatus);
                    if (ret < 0) {
                        LOGE("UpgradeRecoveryProcess failed\n");
                        goto return_over;
                    }
                    break;
                }
            default:
            break;
        }
        sleep(1);
    }

return_over:
	PowerSetWakeUnLock("upgrade");
	pthread_exit(0);
}

int UpgradeRecoveryStart(UPGRADE_STATUS_TYPE_E enUpgradeStatus)
{
    LOGI("Test\n");
    
	int ret = 0;
    pthread_t upgradePid = 0;
	static char bInit = 0;
    int upgradeState = 0;
    
    UpgradeRecoveryGetState(&upgradeState);
    if (upgradeState == 0) {
        LOGI("dont't update, upgradeState:%d\n", upgradeState);
        return 0;
    }
	
	gs_upgradeReocveryStatus = enUpgradeStatus;
	
	if (bInit) {
        LOGW("UpgradeRecoveryStart already start\n");
        return 0;
	}
	
	ret = pthread_create(&upgradePid, NULL, &tskUpgradeRecovery, NULL);
	if (ret != 0) {
		LOGE("pthread_create tskUpgradeRecovery failed!\n");
		return -1;
	}
	
	bInit = 1;
	
	return 0;
}

// 升级恢复开机自检
int UpgradeRecoverySelfCheck(void)
{
    LOGI("Test\n");
    
	int upgradeState = 0;
	int upgradeRetryCnt = 0;
	SYSTEM_WAKEUP_TYPE_E enWakeUpType = 0;
	BATTERY_STATUS_S stBatStatus;
	
    UpgradeRecoveryGetState(&upgradeState);

#ifndef MINI_APP
	UpgradeRecoveryGetRetryCnt(&upgradeRetryCnt);
    if (upgradeState == 1 && upgradeRetryCnt < UPGRADE_RECOVERY_RETRY_NUM)
#else
    if (upgradeState == 1)
#endif /* MINI_APP */
    {
        memset(&stBatStatus, 0, sizeof(stBatStatus));
        SocSubGetBatteryStatus(&stBatStatus);
        SocSubGetWakeUpType(&enWakeUpType);
        if ((enWakeUpType != SYS_WAKEUP_TYPE_KEY_NETCFG) && (stBatStatus.capacity > 30 || stBatStatus.chargingStatus == BAT_CHARGING)) {
            //启动先升级
            UpgradeRecoveryProcess(UPGRADE_STATUS_SHUTDOWN_FAIL);
			PowerSetWakeUnLock("upgrade");
        }
    }
    
	return 0;
}


